package main

import "fmt"

//堆盘子。设想有一堆盘子，堆太高可能会倒下来。因此，在现实生活中，盘子堆到一定高度时，我们就会另外堆一堆盘子。请实现数据结构SetOfStacks，模拟这种行
//为。SetOfStacks应该由多个栈组成，并且在前一个栈填满时新建一个栈。此外，SetOfStacks.push()和SetOfStacks.pop()应该与
//普通栈的操作方法相同（也就是说，pop()返回的值，应该跟只有一个栈时的情况一样）。 进阶：实现一个popAt(int index)方法，根据指定的子栈，执行p
//op操作。
//
// 当某个栈为空时，应当删除该栈。当栈中没有元素或不存在该栈时，pop，popAt 应返回 -1.
//
// 示例1:
//
//  输入：
//["StackOfPlates", "push", "push", "popAt", "pop", "pop"]
//[[1], [1], [2], [1], [], []]
// 输出：
//[null, null, null, 2, 1, -1]
//
//
// 示例2:
//
//  输入：
//["StackOfPlates", "push", "push", "push", "popAt", "popAt", "popAt"]
//[[2], [1], [2], [3], [0], [0], [0]]
// 输出：
//[null, null, null, null, 2, 1, 3]
//
// Related Topics 设计
// 👍 11 👎 0


//leetcode submit region begin(Prohibit modification and deletion)
type StackOfPlates struct {
	Childes [][]int // 子栈, 二维数组
	Cap int // 每个一维数组的容量
}


func Constructor(cap int) StackOfPlates {
	var childes [][]int
	return StackOfPlates{
		Childes: childes,
		Cap:     cap,
	}
}


func (this *StackOfPlates) Push(val int)  {
	// 获取栈中最后一个数组, 并查看是否长度为 cap, 如果小于 cap 直接入栈, 如果大于 cap, 则创建新栈
	if this.Cap == 0 {
		return
	}
	if len(this.Childes) == 0 {
		//  栈中没有任何元素
		this.Childes = append(this.Childes, []int{val})
	} else {
		last := this.Childes[len(this.Childes) - 1]
		if len(last) == this.Cap {
			// 需要新的子栈, 这里不对
			this.Childes = append(this.Childes, []int{val})
		} else {
			// 入盘到最后一个子栈
			last = append(last, val)
			this.Childes[len(this.Childes) - 1] = last
		}
	}
}


func (this *StackOfPlates) Pop() int {
	//pop 操作, 永远出去的是最后一个栈的最后一个元素
	if len(this.Childes) == 0 {
		return -1
	}
	last := this.Childes[len(this.Childes) - 1]
	lastVal := last[len(last) - 1]
	last = last[0:len(last) - 1]
	if len(last) == 0 {
		this.Childes = this.Childes[:len(this.Childes) - 1]
	} else {
		this.Childes[len(this.Childes) - 1] = last
	}

	return lastVal
}


func (this *StackOfPlates) PopAt(index int) int {
	// index 是否在栈的数组中
	// 当前栈中的数组长度
	childLen := len(this.Childes)
	if !(0 <= index && index <= childLen - 1) {
		return -1
	}
	indexChild := this.Childes[index]
	indexChildVal := indexChild[len(indexChild) - 1]
	indexChild = indexChild[:len(indexChild) - 1]
	if len(indexChild) == 0 {
		this.Childes = append(this.Childes[:index], this.Childes[index+1:]...)
	} else {
		this.Childes[index] = indexChild
	}

	return indexChildVal
}


/**
 * Your StackOfPlates object will be instantiated and called as such:
 * obj := Constructor(cap);
 * obj.Push(val);
 * param_2 := obj.Pop();
 * param_3 := obj.PopAt(index);
 */
//leetcode submit region end(Prohibit modification and deletion)


func main() {

	//["StackOfPlates", "pop", "pop", "popAt", "popAt", "pop", "push", "push", "push", "push", "pop", "push", "push", "popAt", "pop", "popAt", "push", "popAt", "pop", "push", "pop", "pop", "pop", "popAt", "push", "pop", "popAt", "pop", "push", "popAt", "popAt", "push", "popAt", "popAt", "push", "pop", "popAt", "popAt", "popAt", "pop", "popAt", "popAt", "push", "popAt", "push", "push", "pop", "popAt", "popAt", "push", "popAt", "push", "pop", "pop", "push", "push", "push", "popAt", "popAt", "pop", "popAt", "pop", "pop", "push", "push"]
	//[[6], [], [], [1], [3], [], [40], [10], [44], [44], [], [24], [42], [4], [], [0], [42], [5], [], [29], [], [], [], [0], [56], [], [4], [], [34], [1], [4], [52], [4], [6], [63], [], [6], [6], [1], [], [6], [2], [47], [1], [45], [52], [], [6], [6], [20], [4], [17], [], [], [43], [6], [30], [2], [3], [], [3], [], [], [51], [46]]

	//测试结果:[null,-1,-1,-1,-1,-1,null,null,null,null,44,null,null,-1,42,10,null,-1,42,null,29,-1,-1,-1,null,56,-1,-1,null,-1,-1,null,-1,-1,null,63,-1,-1,-1,34,-1,-1,null,-1,null,null,52,-1,-1,null,-1,null,17,47,null,null,null,-1,-1,30,-1,43,-1,null,null]

	//期望结果:[null,-1,-1,-1,-1,-1,null,null,null,null,44,null,null,-1,42,24,null,-1,42,null,29,44,10,40,null,56,-1,-1,null,-1,-1,null,-1,-1,null,63,-1,-1,-1,52,-1,-1,null,-1,null,null,52,-1,-1,null,-1,null,17,20,null,null,null,-1,-1,30,-1,6,43,null,null]

	stackOfPlates := Constructor(0)


	//[-1,42,10]
	v := stackOfPlates.Pop() // -1
	fmt.Println(v)
	v = stackOfPlates.Pop() // -1
	fmt.Println(v)
	v = stackOfPlates.PopAt(1) // -1
	fmt.Println(v)
	v = stackOfPlates.PopAt(3) // -1
	fmt.Println(v)
	v = stackOfPlates.Pop() // -1
	fmt.Println(v)
	stackOfPlates.Push(40) // null
	stackOfPlates.Push(10) // null
	stackOfPlates.Push(44) // null
	stackOfPlates.Push(44) // null
	fmt.Printf("%-v \n", stackOfPlates)
	//v = stackOfPlates.Pop() // 44
	//fmt.Printf("%-v \n", stackOfPlates)
	//fmt.Println(v)
	//stackOfPlates.Push(24) // null
	//stackOfPlates.Push(42) // null
	//fmt.Printf("%-v \n", stackOfPlates)
	//v = stackOfPlates.PopAt(4) // 4
	//fmt.Println(v)
	//v = stackOfPlates.Pop() // 42
	//fmt.Println(v)
	//fmt.Printf("%-v \n", stackOfPlates)
	//v = stackOfPlates.PopAt(0) // 24
	//fmt.Println(v)
	//"pop", "pop", "popAt", "popAt", "pop", "push", "push", "push", "push", "pop", "push", "push", "popAt", "pop", "popAt"
	//[], [], [1], [3], [], [40], [10], [44], [44], [], [24], [42], [4], [], [0]
	//-1,-1,-1,-1,-1,null,null,null,null,44,null,null,-1,42,24
	//  "push", "push", "popAt", "pop", "popAt"
}
